//********************************************//
//  Convection Game Engine for XNA Platforms  //
//         created and maintained by          //
//                Colton Fussy                //
//                                            //
//     contact at ConfusingBoat@yahoo.com     //
//                                            //
//   Must include a splash screen displaying  //
//             Convection(TM) logo            //
//                                            //
//        DO NOT REMOVE THIS DESCRIPTION      //
//********************************************//

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

#if WINDOWS
using System.Windows.Forms;
#endif

namespace Convection
{
    #region Main Engine

    public static class GameManager
    {
        #region Internal Variables

        internal static bool mIsInitialized = false;
        internal static ContentManager Content;
        internal static ResourceContentManager DefaultContent;
        internal static GraphicsDeviceManager graphics;
        internal static Game game;

        #endregion

        #region Initialization

        public static void Initialize(Game G, ContentManager c, GraphicsDeviceManager g)
        {
            game = G;
            Content = c;
            DefaultContent = new ResourceContentManager(game.Services, DefaultResources.ResourceManager);
            graphics = g;

            Default.Initialize();
            GraphicsManager.Initialize(c, g);
            SceneManager.Initialize();

            game.Components.Add(new GamerServicesComponent(game));
            game.IsFixedTimeStep = false;

            mIsInitialized = true;
        }

        public static bool IsInitialized
        {
            get
            {
                return mIsInitialized;
            }
        }

        #endregion

        #region Methods

        public static void Exit()
        {
            game.Exit();
        }

        #endregion

        #region Properties

        public static class Default
        {
            internal static void Initialize()
            {
                mDefaultColor = Color.White;
                mDefaultFont = DefaultContent.Load<SpriteFont>("DefaultFont");
            }

            #region Internal Variables

            internal static Color mDefaultColor;
            internal static SpriteFont mDefaultFont;

            #endregion

            public static Color DefaultColor
            {
                get
                {
                    return mDefaultColor;
                }
            }

            public static SpriteFont DefaultFont
            {
                get
                {
                    return mDefaultFont;
                }
            }
        }

        #endregion

        #region User-Customizable Options

        public static string WindowText = "ConvectionGame (v0.0)";

        #endregion
    }

    #endregion

    #region Graphics

    public static class GraphicsManager
    {
        internal static SpriteBatch spriteBatch;

        #region Internal Variables

        #region Framerate Variables

        internal static double currentFramerate;
        internal static double nextUpdateTime;

        #endregion

        internal static Texture2D BasicTexture;
        internal static ContentManager Content;
        internal static bool mIsInitialized = false;
        internal static GraphicsDeviceManager graphics;
        internal static List<ScreenResolution> mAllResolutions = new List<ScreenResolution>();
        internal static List<DisplayConfiguration> mDisplayConfigurations = new List<DisplayConfiguration>();
        internal static Dictionary<string, string> SpriteFiles = new Dictionary<string, string>();
        internal static List<ScreenResolution> mSupportedResolutions = new List<ScreenResolution>();

        #endregion

        #region Systematic Methods

        internal static void Initialize(ContentManager c, GraphicsDeviceManager g)
        {
            Content = c;
            graphics = g;
            mIsInitialized = true;
            spriteBatch = new SpriteBatch(graphics.GraphicsDevice);

            //create the basic texture (1x1 white pixel)
            Color[] BasicTextureColorArray = { Color.White };
            BasicTexture = new Texture2D(graphics.GraphicsDevice, 1, 1);
            BasicTexture.SetData<Color>(BasicTextureColorArray);

            //load resolutions
            LoadResolutions();
            GetSupportedResolutions();

            //load display settings
            LoadDisplaySettings();
            SetDisplayConfiguration("Current");

            graphics.SynchronizeWithVerticalRetrace = false;
            graphics.ApplyChanges();
        }

        internal static void Update(GameTime gameTime)
        {
            foreach (ScrollingBackground background in SpriteManager.mScrollingBackgrounds)
            {
                if (background != null)
                {
                    background.Update();
                }
            }
            for (int p = SpriteManager.mParticleSprites.Count - 1; p >= 0; p--)
            {
                ParticleSprite particle = SpriteManager.mParticleSprites[p];
                if (particle != null)
                {
                    particle.UpdateParticle(gameTime);
                }
            }
            foreach (Sprite sprite in SpriteManager.mSprites)
            {
                if (sprite != null)
                {
                    sprite.Update(gameTime);
                }
            }
            foreach (Text text in SpriteManager.mTexts)
            {
                if (text != null)
                {
                    text.Update(gameTime);
                }
            }
        }

        public static void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(ClearColor);
            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.None);

            #region Draw Positioned

            #region Sorting
            Positioned[] iPositioned = new Positioned[
                SpriteManager.mParticleSprites.Count +
                SpriteManager.mSprites.Count +
                SpriteManager.mTexts.Count];
            int currentIndex = 0;
            for (int p = 0; p < SpriteManager.mParticleSprites.Count; p++)
            {
                iPositioned[currentIndex] = SpriteManager.mParticleSprites[p];
                currentIndex++;
            }
            for (int s = 0; s < SpriteManager.mSprites.Count; s++)
            {
                iPositioned[currentIndex] = SpriteManager.mSprites[s];
                currentIndex++;
            }
            for (int t = 0; t < SpriteManager.mTexts.Count; t++)
            {
                iPositioned[currentIndex] = SpriteManager.mTexts[t];
                currentIndex++;
            }
            Positioned[] mPositioned = iPositioned.OrderBy(x => x.Z).ToArray();
            #endregion

            #region Drawing

            for (int i = 0; i < mPositioned.Length; i++)
            {
                Positioned positioned = mPositioned[i];
                Sprite sprite = new Sprite();
                Text text = new Text();
                if (positioned.PositionedType == PositionedTypes.Sprite)
                {
                    #region Sprite
                    sprite = (Sprite)positioned;
                    if (sprite.Texture != null & sprite.Visible)
                    {
                        #region Area to draw sprite in
                        Rectangle renderRectangle = new Rectangle(Convert.ToInt32(sprite.Position.X) + GraphicsManager.WindowWidth / 2, Convert.ToInt32(-sprite.Position.Y) + GraphicsManager.WindowHeight / 2, sprite.Width, sprite.Height);
                        renderRectangle.Height = Convert.ToInt32((float)renderRectangle.Height * sprite.Scale);
                        renderRectangle.Width = Convert.ToInt32((float)renderRectangle.Width * sprite.Scale);
                        #endregion

                        #region Area of texture to draw

                        Rectangle textureRectangle = new Rectangle(
                            Convert.ToInt32((sprite.mTextureDrawArea.X / sprite.mTexture.Width + sprite.mTextureDrawArea.Width - 1) * .5f * sprite.mTexture.Width),
                            Convert.ToInt32((sprite.mTextureDrawArea.Y / sprite.mTexture.Height + sprite.mTextureDrawArea.Height - 1) * .5f * sprite.mTexture.Height),
                            Convert.ToInt32(sprite.mTexture.Width * sprite.mTextureDrawArea.Width),
                            Convert.ToInt32(sprite.mTexture.Height * sprite.mTextureDrawArea.Height));

                        #endregion
                        spriteBatch.Draw(sprite.Texture, renderRectangle, textureRectangle, sprite.TextureColor, sprite.Rotation, new Vector2(sprite.Width / 2f, sprite.Height / 2f), sprite.Flip, sprite.Position.Z);
                    }
                    #endregion
                }
                else if (positioned.PositionedType == PositionedTypes.Text)
                {
                    #region Text
                    text = (Text)positioned;
                    if (text.Visible)
                    {
                        spriteBatch.DrawString(text.Font, text.DisplayText, new Vector2(text.X + GraphicsManager.WindowWidth / 2, -text.Y + GraphicsManager.WindowHeight / 2), text.TextColor);
                    }
                    #endregion
                }

            }

            #endregion

            #endregion

            #region Draw Engine Info

            #region Framerate
            if (DisplayFramerate)
            {
                Color fpsColor = Color.White;
                if (gameTime.TotalGameTime.TotalMilliseconds > nextUpdateTime)
                {
                    currentFramerate = Math.Round((1.0 / gameTime.ElapsedRealTime.TotalSeconds), 1);
                    nextUpdateTime = gameTime.TotalGameTime.TotalMilliseconds + mDisplayUpdateRate;
                }
                if (currentFramerate >= 60)
                {
                    fpsColor = Color.Lime;
                }
                else if (currentFramerate < 60 & currentFramerate >= 30)
                {
                    fpsColor = Color.Yellow;
                }
                else if (currentFramerate < 30 & currentFramerate >= 15)
                {
                    fpsColor = Color.Orange;
                }
                else
                {
                    fpsColor = Color.Red;
                }
                spriteBatch.Draw(BasicTexture, new Rectangle(4, 4, (currentFramerate.ToString() + " fps").Length * 14 + 2, 27), fpsColor);
                spriteBatch.Draw(BasicTexture, new Rectangle(5, 5, (currentFramerate.ToString() + " fps").Length * 14, 25), Color.Black);
                spriteBatch.DrawString(GameManager.Default.DefaultFont, currentFramerate.ToString() + " fps", new Vector2(9, 8), fpsColor);
            }
            #endregion

            #region Sprites
            if (DisplaySprites)
            {
                Color spriteNumberColor = Color.White;
                string countString = (SpriteManager.mParticleSprites.Count + SpriteManager.mSprites.Count).ToString() + " sprites";
                spriteBatch.Draw(BasicTexture, new Rectangle(4, 35, (countString).Length * 14 + 2, 27), spriteNumberColor);
                spriteBatch.Draw(BasicTexture, new Rectangle(5, 36, (countString).Length * 14, 25), Color.Black);
                spriteBatch.DrawString(GameManager.Default.DefaultFont, countString, new Vector2(9, 39), spriteNumberColor);
            }
            #endregion

            #endregion

            spriteBatch.End();
        }

        #endregion

        #region Display Configuration

        public static void AutoSetGraphics()
        {
            graphics.PreferredBackBufferHeight = mSupportedResolutions.Last().Height;
            graphics.PreferredBackBufferWidth = mSupportedResolutions.Last().Width;
            if (!graphics.IsFullScreen)
            {
                graphics.ToggleFullScreen();
            }
            graphics.ApplyChanges();
        }

        public static void GetSupportedResolutions()
        {
            int MaxHeight = 0;
            int MaxWidth = 0;

            MaxHeight = Screen.GetBounds(new System.Drawing.Point(0, 0)).Height;
            MaxWidth = Screen.GetBounds(new System.Drawing.Point(0, 0)).Width;

            foreach (ScreenResolution res in mAllResolutions)
            {
                if (res.Height <= MaxHeight & res.Width <= MaxWidth)
                    mSupportedResolutions.Add(res);
            }
        }

        static void LoadDisplaySettings()
        {
            if (IsInitialized)
            {
                #region Creating Nonexisting File

                if (!File.Exists("DisplayConfigurations.ccf"))
                {
                    #region Default Display Configurations Text
                    string DefaultDisplayConfigurationsText =
                        "[displayconfigurations=Default]\r\n\r\n[configuration=Auto]\r\nfullscreen=false\r\nresolutionHeight=600\r\nresolutionWidth=800\r\n[/configuration]\r\n\r\n[configuration=Current]\r\nfullscreen=false\r\nresolutionHeight=600\r\nresolutionWidth=800\r\n[/configuration]\r\n\r\n[/displayconfigurations]";
                    #endregion
                    File.WriteAllText("DisplayConfigurations.ccf", DefaultDisplayConfigurationsText);
                }

                #endregion

                #region Reading Existing File
                if (File.Exists("DisplayConfigurations.ccf"))
                {
                    StreamReader sReader = new StreamReader("DisplayConfigurations.ccf");
                    string linebuffer = "";

                    while (!sReader.EndOfStream)
                    {
                        linebuffer = sReader.ReadLine();

                        if (linebuffer.StartsWith("[configuration="))
                        {
                            mDisplayConfigurations.Add(new DisplayConfiguration(GetParamValue(linebuffer.Remove(linebuffer.IndexOf("]")))));
                        }
                        else if (linebuffer.StartsWith("fullscreen="))
                        {
                            bool.TryParse(GetParamValue(linebuffer), out mDisplayConfigurations.Last().Fullscreen);
                        }
                        else if (linebuffer.StartsWith("resolutionHeight="))
                        {
                            int.TryParse(GetParamValue(linebuffer), out mDisplayConfigurations.Last().Resolution.Height);
                        }
                        else if (linebuffer.StartsWith("resolutionWidth="))
                        {
                            int.TryParse(GetParamValue(linebuffer), out mDisplayConfigurations.Last().Resolution.Width);
                        }
                    }

                    sReader.Close();

                }
                #endregion
            }
        }

        static void LoadResolutions()
        {
            #region Creating Nonexisting File
            if (!File.Exists("Resolutions.ccf"))
            {
                #region Default Resolutions Text
                string DefaultResolutionsText =
                    "320x240\r\n640x480\r\n800x600\r\n1024x768\r\n1152x864\r\n1280x768\r\n1280x800\r\n1280x960\r\n1280x1024\r\n1366x768\r\n1440x900\r\n1600x1200\r\n1680x1050\r\n1920x1080\r\n1920x1200";
                #endregion
                File.WriteAllText("Resolutions.ccf", DefaultResolutionsText);
            }
            #endregion

            #region Reading Existing File
            if (File.Exists("Resolutions.ccf"))
            {
                StreamReader resLoader = new StreamReader("Resolutions.ccf");
                string linebuffer = "";

                while (!resLoader.EndOfStream)
                {
                    int width = 0;
                    int height = 0;
                    linebuffer = resLoader.ReadLine();
                    int.TryParse(linebuffer.Remove(linebuffer.IndexOf("x")), out width);
                    int.TryParse(linebuffer.Remove(0, linebuffer.IndexOf("x") + 1), out height);
                    if (width > 0 & height > 0)
                    {
                        mAllResolutions.Add(new ScreenResolution(width, height));
                    }
                }
            }
            #endregion
        }

        static void SetDisplayConfiguration(DisplayConfiguration Configuration)
        {
            mWindowHeight = Configuration.Resolution.Height;
            mWindowWidth = Configuration.Resolution.Width;
            graphics.IsFullScreen = Configuration.Fullscreen;
            graphics.PreferredBackBufferHeight = WindowHeight;
            graphics.PreferredBackBufferWidth = WindowWidth;
            graphics.ApplyChanges();
        }

        static void SetDisplayConfiguration(string ConfigurationName)
        {
            foreach (DisplayConfiguration Configuration in DisplayConfigurations)
            {
                if (Configuration.Name == ConfigurationName)
                {
                    SetDisplayConfiguration(Configuration);
                    break;
                }
            }
        }

        #endregion

        #region Methods

        static string GetParamValue(string linebuffer)
        {
            return linebuffer.Remove(0, linebuffer.IndexOf("=") + 1);
        }

        static void UpdateGraphics()
        {
            graphics.PreferredBackBufferHeight = WindowHeight;
            graphics.PreferredBackBufferWidth = WindowWidth;
            graphics.ApplyChanges();
        }

        #endregion

        #region Properties

        public static bool IsInitialized
        {
            get
            {
                return mIsInitialized;
            }
        }

        public static double CurrentFramerate
        {
            get { return currentFramerate; }
        }

        public static List<DisplayConfiguration> DisplayConfigurations
        {
            get
            {
                return mDisplayConfigurations;
            }
        }

        public static GraphicsDeviceManager DeviceManager
        {
            get { return graphics; }
        }

        public static List<ScreenResolution> SupportedResolutions
        {
            get
            {
                return mSupportedResolutions;
            }
        }

        #endregion

        #region User-Customizable Options

        #region Internal Variables

        internal static bool mDisplayFramerate = false;
        internal static bool mDisplaySprites = false;
        internal static int mDisplayUpdateRate = 500;
        internal static int mWindowHeight = 600;
        internal static int mWindowWidth = 800;

        #endregion

        public static Color ClearColor = Color.CornflowerBlue;
        public static CoordinateSystemType CoordinateSystem = CoordinateSystemType.Pixel;
        public static bool DisplayFramerate
        {
            get
            {
                return mDisplayFramerate;
            }
            set
            {
                mDisplayFramerate = value;
            }
        }
        public static bool DisplaySprites
        {
            get
            {
                return mDisplaySprites;
            }
            set
            {
                mDisplaySprites = value;
            }
        }
        public static int DisplayUpdateRate
        {
            get { return mDisplayUpdateRate; }
            set { mDisplayUpdateRate = value; }
        }
        public static int WindowHeight
        {
            get
            {
                return mWindowHeight;
            }
            set
            {
                mWindowHeight = value;
                UpdateGraphics();
            }
        }
        public static int WindowWidth
        {
            get
            {
                return mWindowWidth;
            }
            set
            {
                mWindowWidth = value;
                UpdateGraphics();
            }
        }

        #endregion

    }

    public static class SpriteManager
    {
        public static void AddParticleSprite(ParticleSprite particle)
        {
            if (!mParticleSprites.Contains(particle))
            {
                mParticleSprites.Add(particle);
            }
        }

        public static void AddParticleSprites(ParticleSprite particle, int numParticles)
        {
            for (int i = 0; i < numParticles; i++)
            {
                ParticleSprite nParticle = particle;
                mParticleSprites.Add(nParticle);
            }
        }

        public static void AddParticleSprites(List<ParticleSprite> particles)
        {
            AddParticleSprites(particles.ToArray());
        }

        public static void AddParticleSprites(ParticleSprite[] particles)
        {
            for (int i = 0; i < particles.Length; i++)
            {
                if (!mParticleSprites.Contains(particles[i]))
                {
                    mParticleSprites.Add(particles[i]);
                }
            }
        }

        public static void AddSprite(Sprite sprite)
        {
            if (!mSprites.Contains(sprite))
            {
                mSprites.Add(sprite);
            }
        }

        public static void AddSprites(List<Sprite> sprites)
        {
            AddSprites(sprites.ToArray());
        }

        public static void AddSprites(Sprite[] sprites)
        {
            for (int i = 0; i < sprites.Length; i++)
            {
                if (!mSprites.Contains(sprites[i]))
                {
                    mSprites.Add(sprites[i]);
                }
            }
        }

        public static void RemoveSprite(Sprite sprite)
        {
            if (mSprites.Contains(sprite))
            {
                mSprites.Remove(sprite);
            }
        }

        public static void RemoveSprites(List<Sprite> sprites)
        {
            RemoveSprites(sprites.ToArray());
        }

        public static void RemoveSprites(Sprite[] sprites)
        {
            for (int i = 0; i < sprites.Length; i++)
            {
                if (mSprites.Contains(sprites[i]))
                {
                    mSprites.Remove(sprites[i]);
                }
            }
        }

        public static void AddScrollingBackground(ScrollingBackground scrollingBackground)
        {
            if (!mScrollingBackgrounds.Contains(scrollingBackground))
            {
                mScrollingBackgrounds.Add(scrollingBackground);
                scrollingBackground.Activate();
            }
        }

        public static void RemoveScrollingBackground(ScrollingBackground scrollingBackground)
        {
            if (mScrollingBackgrounds.Contains(scrollingBackground))
            {
                scrollingBackground.Destroy();
                mScrollingBackgrounds.Remove(scrollingBackground);
            }
        }

        public static void AddText(Text text)
        {
            if (!mTexts.Contains(text))
            {
                mTexts.Add(text);
            }
        }

        public static void RemoveText(Text text)
        {
            if (mTexts.Contains(text))
            {
                mTexts.Remove(text);
            }
        }

        #region Internal Variables

        internal static List<ParticleSprite> mParticleSprites = new List<ParticleSprite>();
        internal static List<ScrollingBackground> mScrollingBackgrounds = new List<ScrollingBackground>();
        internal static List<Sprite> mSprites = new List<Sprite>();
        internal static List<Text> mTexts = new List<Text>();

        #endregion

        public static List<ParticleSprite> ParticleSprites
        {
            get
            {
                ParticleSprite[] returnParticles = new ParticleSprite[mParticleSprites.Count];
                mParticleSprites.CopyTo(returnParticles);
                return returnParticles.ToList();
            }
        }

        public static List<ScrollingBackground> ScrollingBackgrounds
        {
            get
            {
                ScrollingBackground[] returnBackgrounds = new ScrollingBackground[mScrollingBackgrounds.Count];
                mScrollingBackgrounds.CopyTo(returnBackgrounds);
                return returnBackgrounds.ToList();
            }
        }

        public static List<Sprite> Sprites
        {
            get
            {
                Sprite[] returnSprites = new Sprite[mSprites.Count];
                mSprites.CopyTo(returnSprites);
                return returnSprites.ToList();
            }
        }

        public static List<Text> Texts
        {
            get
            {
                Text[] returnTexts = new Text[mTexts.Count];
                mTexts.CopyTo(returnTexts);
                return returnTexts.ToList();
            }
        }
    }

    public sealed class DisplayConfiguration
    {
        public DisplayConfiguration(string name)
        {
            Name = name;
        }
        public string Name = "";
        public bool Fullscreen = false;
        public ScreenResolution Resolution = new ScreenResolution();
    }

    public class ScrollingBackground
    {
        public ScrollingBackground(Texture2D backgroundTexture)
        {
            Height = backgroundTexture.Height;
            Width = backgroundTexture.Width;
            Texture = backgroundTexture;
        }

        public ScrollingBackground(Texture2D backgroundTexture, Vector2 position)
        {
            Position = position;
            Height = backgroundTexture.Height;
            Width = backgroundTexture.Width;
            Texture = backgroundTexture;
        }

        public ScrollingBackground(Texture2D backgroundTexture, int height, int width)
        {
            Height = height;
            Width = width;
            Texture = backgroundTexture;
        }

        #region Internal Methods

        internal void Activate()
        {
            SetBackground(Texture);
        }

        internal void Destroy()
        {
            foreach (List<Sprite> row in Rows)
            {
                SpriteManager.RemoveSprites(row);
            }
        }

        internal void Update()
        {
            int currentRow = 0;
            foreach (List<Sprite> row in Rows)
            {
                int currentColumn = 0;
                foreach (Sprite sprite in row)
                {
                    #region Set Visibility

                    if (TileDirection != TileDirections.Both)
                    {
                        if (TileDirection == TileDirections.Horizontal &
                            currentRow != Rows.Count / 2)
                        {
                            sprite.Visible = false;
                        }
                        else if (TileDirection == TileDirections.Vertical &
                            currentColumn != row.Count / 2)
                        {
                            sprite.Visible = false;
                        }
                        else
                        {
                            sprite.Visible = true;
                        }
                    }

                    #endregion

                    #region Checking X

                    #region Left Moving
                    if (sprite.X < -GraphicsManager.WindowWidth / 2 - sprite.Width / 2 &
                        sprite.VelocityX <= 0)
                    {
                        int placementIndex = 0;
                        if (currentColumn > 0)
                        {
                            placementIndex = currentColumn - 1;
                        }
                        else
                        {
                            placementIndex = row.Count - 1;
                        }
                        sprite.X = row[placementIndex].X + sprite.Width;
                    }
                    #endregion

                    #region Right Moving
                    else if (sprite.X > GraphicsManager.WindowWidth / 2 + sprite.Width / 2 &
                        sprite.VelocityX >= 0)
                    {
                        int placementIndex = 0;
                        if (currentColumn < row.Count - 1)
                        {
                            placementIndex = currentColumn + 1;
                        }
                        else
                        {
                            placementIndex = 0;
                        }
                        sprite.X = row[placementIndex].X - sprite.Width;
                    }
                    #endregion

                    #endregion

                    #region Checking Y

                    #region Down Moving
                    if (sprite.Y < -GraphicsManager.WindowHeight / 2 - sprite.Height / 2 &
                        sprite.VelocityY <= 0)
                    {
                        int placementIndex = 0;
                        if (currentRow > 0)
                        {
                            placementIndex = currentRow - 1;
                        }
                        else
                        {
                            placementIndex = Rows.Count - 1;
                        }
                        sprite.Y = Rows[placementIndex][currentColumn].Y + sprite.Height;
                    }
                    #endregion

                    #region Up Moving
                    else if (sprite.Y > GraphicsManager.WindowHeight / 2 + sprite.Height / 2 &
                        sprite.VelocityY >= 0)
                    {
                        int placementIndex = 0;
                        if (currentRow < Rows.Count - 1)
                        {
                            placementIndex = currentRow + 1;
                        }
                        else
                        {
                            placementIndex = 0;
                        }
                        sprite.Y = Rows[placementIndex][currentColumn].Y - sprite.Height;
                    }
                    #endregion

                    #endregion

                    currentColumn++;
                }
                currentRow++;
            }
        }

        #endregion

        #region Internal Variables
        internal List<List<Sprite>> Rows = new List<List<Sprite>>();
        internal int mHeight;
        internal Vector2 mPosition = new Vector2();
        internal TileDirections mTileDirection = TileDirections.Both;
        internal float mVelocityX;
        internal float mVelocityY;
        internal int mWidth;
        #endregion

        #region Properties

        public int Height
        {
            get { return mHeight; }
            set
            {
                mHeight = value;
                foreach (List<Sprite> row in Rows)
                {
                    foreach (Sprite sprite in row)
                    {
                        sprite.Height = value;
                    }
                }
            }
        }
        public Vector2 Position
        {
            get { return mPosition; }
            set
            {
                mPosition = value;
                Activate();
            }
        }
        public Texture2D Texture;
        public TileDirections TileDirection
        {
            get { return mTileDirection; }
            set { mTileDirection = value; }
        }
        public float VelocityX
        {
            get { return mVelocityX; }
            set
            {
                mVelocityX = value;
                foreach (List<Sprite> row in Rows)
                {
                    foreach (Sprite sprite in row)
                    {
                        sprite.VelocityX = value;
                    }
                }
            }
        }
        public float VelocityY
        {
            get { return mVelocityY; }
            set
            {
                mVelocityY = value;
                foreach (List<Sprite> row in Rows)
                {
                    foreach (Sprite sprite in row)
                    {
                        sprite.VelocityY = value;
                    }
                }
            }
        }
        public float X
        {
            get { return mPosition.X; }
            set { mPosition.X = value; }
        }
        public float Y
        {
            get { return mPosition.Y; }
            set { mPosition.Y = value; }
        }
        public int Width
        {
            get { return mWidth; }
            set
            {
                mWidth = value;
                foreach (List<Sprite> row in Rows)
                {
                    foreach (Sprite sprite in row)
                    {
                        sprite.Width = value;
                    }
                }
            }
        }

        #endregion

        #region Methods

        public void SetBackground(Texture2D backgroundTexture)
        {
            foreach (List<Sprite> row in Rows)
            {
                SpriteManager.RemoveSprites(row);
            }
            Rows.Clear();
            Texture = backgroundTexture;
            int heightScale = Convert.ToInt32((float)GraphicsManager.WindowHeight / (float)Height) * 4;
            int widthScale = Convert.ToInt32((float)GraphicsManager.WindowWidth / (float)Width) * 4;
            for (int i = -heightScale / 2; i < heightScale / 2; i++)
            {
                List<Sprite> row = new List<Sprite>();
                for (int j = -widthScale / 2; j < widthScale / 2; j++)
                {
                    Sprite piece = new Sprite(Texture);
                    piece.VelocityX = VelocityX;
                    piece.VelocityY = VelocityY;
                    piece.X = j * Width + Position.X;
                    piece.Y = i * Height + Position.Y;
                    row.Add(piece);
                }
                Rows.Add(row);
            }
            foreach (List<Sprite> row in Rows)
            {
                SpriteManager.AddSprites(row);
            }
        }

        public void Shift(Vector2 shiftCoordinates)
        {
            foreach (List<Sprite> row in Rows)
            {
                foreach (Sprite sprite in row)
                {
                    sprite.X += shiftCoordinates.X;
                    sprite.Y += shiftCoordinates.Y;
                }
            }
        }

        #endregion
    }

    public enum TileDirections
    {
        Both,
        Horizontal,
        Vertical
    }

    public abstract class Positioned
    {
        #region Internal Variables

        internal PositionedTypes PositionedType;

        #endregion

        #region Properties

        public Vector3 Position = new Vector3();
        public float Rotation;
        public float RotationVelocity;
        public float VelocityX = 0;
        public float VelocityY = 0;
        public bool Visible = true;
        public float X
        {
            get { return Position.X; }
            set { Position.X = value; }
        }
        public float Y
        {
            get { return Position.Y; }
            set { Position.Y = value; }
        }
        public float Z
        {
            get { return Position.Z; }
            set { Position.Z = value; }
        }

        #endregion

        #region Virtual Methods

        internal virtual void Update(GameTime gameTime)
        {
            float timeOffset = (float)gameTime.ElapsedGameTime.TotalSeconds;

            //updating position
            Position.X += VelocityX * 10 * timeOffset;
            Position.Y += VelocityY * 10 * timeOffset;

            //updating rotation
            Rotation += RotationVelocity * timeOffset;
        }

        #endregion
    }

    public class ColoredRectangle : Positioned
    {
        public ColoredRectangle()
        {
            PositionedType = PositionedTypes.ColoredRectangle;
        }

        public Color TextureColor = GameManager.Default.DefaultColor;
    }

    #region Sprite & Associated

    public class Sprite : Positioned
    {
        public Sprite()
        {
            PositionedType = PositionedTypes.Sprite;
            mName = "Sprite" + SpriteManager.mSprites.Count.ToString();
        }

        public Sprite(Texture2D texture)
        {
            PositionedType = PositionedTypes.Sprite;
            mTexture = texture;
            Height = texture.Height;
            Width = texture.Width;
        }

        #region Internal Methods

        internal override void Update(GameTime gameTime)
        {
            float timeOffset = (float)gameTime.ElapsedGameTime.TotalSeconds;

            //updating alpha
            Alpha += AlphaRate * timeOffset;

            //updating scale
            Scale += ScaleRate * timeOffset;

            base.Update(gameTime);
        }

        #endregion

        #region Internal Variables

        internal List<Point> mCollisionPolygonVertices = new List<Point>();
        internal Rectangle mDrawRectangle = new Rectangle(0, 0, 32, 32);
        internal string mName = "";
        internal string mOwner = "";
        internal float mScale = 1;
        internal Texture2D mTexture;
        internal FloatingRectangle mTextureDrawArea = new FloatingRectangle(0, 0, 1, 1);
        internal string mTextureLocation = "";

        #endregion

        #region Properties

        public float Alpha
        {
            get
            {
                return (float)(TextureColor.A) / 255f;
            }
            set
            {
                TextureColor.A = (byte)(value * 255);
            }
        }
        public float AlphaRate;
        public bool Animated = false;
        public Direction AnimationStringDirection = Direction.Horizontal;
        public bool CollidingWith(Sprite sprite)
        {
            float radiusThis = (Height + Width) * Scale / 2f;
            float radiusThat = (sprite.Height + sprite.Width) * Scale / 2f;
            float radiusAverage = Math.Abs((radiusThis + radiusThat) / 2f);
            if (Math.Abs(Position.X - sprite.Position.X) <= radiusAverage &
                Math.Abs(Position.Y - sprite.Position.Y) <= radiusAverage)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        public List<Point> CollisionPolygonVertices
        {
            get { return mCollisionPolygonVertices; }
        }
        public CollisionDetectionType CollisionDetection = CollisionDetectionType.Radial;
        public Rectangle DrawRectangle
        {
            get
            {
                Rectangle returnRectangle = mDrawRectangle;
                returnRectangle.Height *= Convert.ToInt32(mScale);
                returnRectangle.Width *= Convert.ToInt32(mScale);
                return returnRectangle;
            }
        }
        public int Height
        {
            get { return mDrawRectangle.Height; }
            set { mDrawRectangle.Height = value; }
        }
        public bool InsideView
        {
            get
            {
                float radiusThis = Math.Abs((Height + Width) * Scale / 2f);
                if (Math.Abs(Position.X) > GraphicsManager.WindowWidth / 2f + radiusThis ||
                    Math.Abs(Position.Y) > GraphicsManager.WindowHeight / 2f + radiusThis)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
        }
        public SpriteEffects Flip = SpriteEffects.None;
        public string Name
        {
            get { return mName; }
        }
        public string Owner
        {
            get { return mOwner; }
        }
        public float Scale
        {
            get { return mScale; }
            set { mScale = value; }
        }
        public float ScaleRate = 0;
        public Texture2D Texture
        {
            get { return mTexture; }
            set
            {
                mTexture = value;
                Height = mTexture.Height;
                Width = mTexture.Width;
            }
        }
        public Color TextureColor = new Color(new Vector4(1));
        public FloatingRectangle TextureDrawArea
        {
            get { return mTextureDrawArea; }
        }
        public Vector2 TextureDrawAreaOrigin
        {
            get { return new Vector2(mTextureDrawArea.X, mTextureDrawArea.Y); }
            set
            {
                mTextureDrawArea.X = Convert.ToInt32(value.X);
                mTextureDrawArea.Y = Convert.ToInt32(value.Y);
            }
        }
        public float TextureDrawAreaHeight
        {
            get { return mTextureDrawArea.Height; }
            set { mTextureDrawArea.Height = value; }
        }
        public float TextureDrawAreaWidth
        {
            get { return mTextureDrawArea.Width; }
            set { mTextureDrawArea.Width = value; }
        }
        public float TextureDrawAreaX
        {
            get { return mTextureDrawArea.X; }
            set { mTextureDrawArea.X = value; }
        }
        public float TextureDrawAreaY
        {
            get { return mTextureDrawArea.Y; }
            set { mTextureDrawArea.Y = value; }
        }
        public int Width
        {
            get { return mDrawRectangle.Width; }
            set { mDrawRectangle.Width = value; }
        }

        #endregion
    }

    public class ParticleSprite : Sprite
    {
        public ParticleSprite()
        {
            PositionedType = PositionedTypes.Sprite;
        }

        public ParticleSprite(Texture2D texture)
        {
            PositionedType = PositionedTypes.Sprite;
            Texture = texture;
        }

        public RemovalEvents RemovalEvent = new RemovalEvents();

        internal void UpdateParticle(GameTime gameTime)
        {
            if (RemovalEvent.Alpha0 && Alpha <= 0)
            {
                SpriteManager.mParticleSprites.Remove(this);
            }
            else if (RemovalEvent.OutsideView && !InsideView)
            {
                SpriteManager.mParticleSprites.Remove(this);
            }
            Update(gameTime);
        }
    }

    #endregion

    #region Text & Associated

    public class Text : Positioned
    {
        public Text()
        {
            PositionedType = PositionedTypes.Text;
        }

        public Text(string text)
        {
            PositionedType = PositionedTypes.Text;
            DisplayText = text;
        }

        public Text(SpriteFont font, string text)
        {
            PositionedType = PositionedTypes.Text;
            Font = font;
            DisplayText = text;
        }

        #region Internal Methods

        internal override void Update(GameTime gameTime)
        {
            float timeOffset = (float)gameTime.ElapsedGameTime.TotalSeconds;

            //updating alpha
            Alpha += AlphaRate * timeOffset;

            base.Update(gameTime);
        }

        #endregion

        #region Properties

        public float Alpha
        {
            get
            {
                return (float)(TextColor.A) / 255f;
            }
            set
            {
                TextColor.A = (byte)(value * 255);
            }
        }
        public float AlphaRate;
        public string DisplayText = "";
        public SpriteFont Font = GameManager.Default.DefaultFont;
        public Color TextColor = GameManager.Default.DefaultColor;
        public List<TextEffect> TextEffects = new List<TextEffect>();

        #endregion
    }

    public abstract class TextEffect
    {
        #region Internal Variables

        internal TextEffectTypes mEffectType;

        #endregion

        public TextEffectTypes EffectType
        {
            get
            {
                return mEffectType;
            }
        }
    }

    public class TextGlow : TextEffect
    {
        public TextGlow()
        {
            mEffectType = TextEffectTypes.Glow;
        }

        public Color GlowColor = GameManager.Default.DefaultColor;
    }

    public class TextShadow : TextEffect
    {
        public TextShadow()
        {
            mEffectType = TextEffectTypes.Shadow;
        }
    }

    #endregion

    #region Structs

    public struct FloatingRectangle
    {
        public FloatingRectangle(float x, float y, float width, float height)
        {
            Width = width;
            Height = height;
            X = x;
            Y = y;
        }
        public float Width;
        public float Height;
        public float X;
        public float Y;
    }

    public struct RemovalEvents
    {
        public bool Alpha0;
        public bool OutsideView;
    }

    public struct ScreenResolution
    {
        public ScreenResolution(int width, int height)
        {
            Height = height;
            Width = width;
        }
        public int Height;
        public int Width;
    }

    #endregion

    #endregion

    #region Logic

    public static class LogicManager
    {
        #region Internal Variables

        internal static double mNextUpdateTime;

        #endregion

        #region Methods

        public static void Update(GameTime gameTime)
        {
            GraphicsManager.Update(gameTime);
            PlayerManager.Update();
            SceneManager.Update(gameTime);
        }

        #endregion

        #region Properties

        public static bool UseCollisionDetection = false;

        #endregion
    }

    #endregion

    #region Players

    public static class PlayerManager
    {
        #region Methods

        internal static void Update()
        {
            for (int i = 0; i < mPlayers.Count; i++)
            {
                mPlayers[i].Update();
            }
        }

        public static void AddPlayer()
        {
            if (mPlayers.Count < 4)
            {
                PlayerIndex newIndex = PlayerIndex.One;
                switch (mPlayers.Count)
                {
                    case 0:
                        newIndex = PlayerIndex.One;
                        break;
                    case 1:
                        newIndex = PlayerIndex.Two;
                        break;
                    case 2:
                        newIndex = PlayerIndex.Three;
                        break;
                    case 3:
                        newIndex = PlayerIndex.Four;
                        break;
                    default:
                        break;
                }
                mPlayers.Add(new Player(newIndex));
            }
        }

        #endregion

        #region Properties

        #region Internal Variables

        internal static List<Player> mPlayers = new List<Player>();

        #endregion

        public static Player GetPlayer(PlayerIndex playerIndex)
        {
            for (int i = 0; i < mPlayers.Count; i++)
            {
                if (mPlayers[i].Index == playerIndex)
                {
                    return mPlayers[i];
                }
            }
            return null;
        }
        public static List<Player> Players
        {
            get
            {
                return mPlayers;
            }
        }

        #endregion
    }

    public class Player
    {
        internal Player()
        {

        }

        internal Player(PlayerIndex playerIndex)
        {
            mController = new XboxGamePad(playerIndex);
            mIndex = playerIndex;
        }

        public Player(SignedInGamer signedInGamer)
        {
            mXboxGamer = signedInGamer;
            mIndex = mXboxGamer.PlayerIndex;
            mController = new XboxGamePad(mIndex);
        }

        #region Methods

        internal void Initialize()
        {
            PlayerManager.mPlayers.Add(this);
        }

        internal void Update()
        {
            mController.Update();
        }

        #endregion

        #region Properties

        #region Internal Variables

        internal XboxGamePad mController;
        internal PlayerIndex mIndex;
        internal PlayerProfile mProfile = new PlayerProfile();
        internal SignedInGamer mXboxGamer;

        #endregion

        public XboxGamePad Controller
        {
            get
            {
                return mController;
            }
        }
        public PlayerIndex Index
        {
            get
            {
                return mIndex;
            }
        }
        public PlayerProfile Profile
        {
            get
            {
                return mProfile;
            }
        }
        public SignedInGamer XboxGamer
        {
            get
            {
                return mXboxGamer;
            }
        }

        #endregion
    }

    public class PlayerProfile
    {
        #region Internal Variables

        internal Dictionary<string, object> mProfileProperties = new Dictionary<string, object>();
        internal SignedInGamer mXboxGamer;

        #endregion

        public string GamerTag
        {
            get
            {
                return XboxGamer.Gamertag;
            }
        }
        public Dictionary<string, object> ProfileProperties
        {
            get
            {
                return mProfileProperties;
            }
        }
        public SignedInGamer XboxGamer
        {
            get
            {
                return mXboxGamer;
            }
        }
    }

    #endregion

    #region Scenes

    public static class SceneManager
    {
        #region Internal Variables

        internal static List<Scene> mAvailableScenes = new List<Scene>();
        internal static int mCurrentScene = 0;

        #endregion

        #region Methods

        internal static void Initialize()
        {
            GoToScene(0);
        }

        internal static void Update(GameTime gameTime)
        {
            if (AvailableScenes[mCurrentScene].IsInitialized)
            {
                AvailableScenes[mCurrentScene].mCurrentTime = gameTime.TotalGameTime.TotalSeconds;
                AvailableScenes[mCurrentScene].GameCycle();
            }
            else
            {
                AvailableScenes[mCurrentScene].Initialize();
            }
        }

        public static void AddScene(Scene scene)
        {
            if (!mAvailableScenes.Contains(scene))
            {
                mAvailableScenes.Add(scene);
                scene.mIndex = mAvailableScenes.IndexOf(mAvailableScenes.Last());
            }
        }

        public static void GoToScene(Scene scene)
        {
            if (AvailableScenes.Contains(scene))
            {
                CurrentScene.Destroy();
                mCurrentScene = scene.Index;
                GC.Collect();
            }
        }

        public static void GoToScene(int index)
        {
            GoToScene(AvailableScenes[index]);
        }

        public static void RemoveScene(Scene scene)
        {
            if (mAvailableScenes.Contains(scene))
            {
                mAvailableScenes.Remove(scene);
            }
        }

        #endregion

        #region Properties

        public static List<Scene> AvailableScenes
        {
            get
            {
                return mAvailableScenes;
            }
        }

        public static Scene CurrentScene
        {
            get
            {
                return AvailableScenes[mCurrentScene];
            }
        }

        #endregion
    }

    public abstract class Scene
    {
        #region Internal Variables

        internal double mCurrentTime;
        internal bool mIsInitialized = false;
        internal int mIndex = 0;

        #endregion

        #region Properties

        public ContentManager Content
        {
            get
            {
                return GraphicsManager.Content;
            }
        }

        public double CurrentTime
        {
            get
            {
                return mCurrentTime;
            }
        }

        public bool IsInitialized
        {
            get
            {
                return mIsInitialized;
            }
        }

        public int Index
        {
            get
            {
                return mIndex;
            }
        }

        #endregion

        #region Virtual Methods

        public virtual void Initialize()
        {
            if (!IsInitialized)
            {
                mIsInitialized = true;
            }
        }

        public virtual void GameCycle()
        {

        }

        public virtual void Destroy()
        {

        }

        #endregion
    }

    #endregion
}

#region Internal Enums

internal enum PositionedTypes
{
    ColoredRectangle,
    Sprite,
    Text
}

#endregion

#region Public Enums

public enum CollisionDetectionType
{
    None,
    PerPixel,
    Polygon,
    Radial,
    Rectangle
}

public enum CoordinateSystemType
{
    Grid,
    Pixel
}

public enum Direction
{
    Down,
    Horizontal,
    Left,
    Right,
    Up,
    Vertical
}

public enum TextEffectTypes
{
    Glow,
    Shadow
}

#endregion